<?php

namespace App\Models\Ddaman;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use App\Models\common\Base;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use mysql_xdevapi\Exception;

class Workflow extends Base
{
    use HasFactory,SoftDeletes;

    protected $table = "workflow";

    //const CREATED_AT = null;
    //const UPDATED_AT = null;

    const FLOW_INTERNS    = 1;//入职
    const FLOW_LEAVE      = 2;//请假
    const FLOW_PERSONNEL  = 3;//人事变动

    protected $fillable = [
        'guid','work_no','design_id','user_id','step','state','tags','handle','remark','is_filed','filed_time','status','is_cancel','cancel_time',
        'company_id','school_id','student_id'
    ];


    public $rule = [
        'design_id' => 'required',
    ];

    public $editRule = [
        'guid' => 'required',
        'design_id' => 'required',
    ];

    public $message = [
        'guid.required' => '标识必须',
        'design_id.required' => '提交类型必须',
    ];

    /*
     * 获取列表
     * */
    public function getList( $param = [] )
    {
        $limit = isset($param['limit']) ? $param['limit'] : 10;
        $where = [];

        if (isset($param['keywords']) && $param['keywords']){
            $keywords = trim($param['keywords']);
            $where[] = ['name','like',"%$keywords%"];
        }

        $field = array_merge(['id'],$this->fillable);
        $list = $this->where($where)->orderBy('id','desc')->select($field)->paginate($limit);

        return $list;

    }


    /*
     * 保存工作表
     * */
    public function changes( $data , $rule=[] )
    {
        $validator = Validator::make( $data ,$rule ,$this->message);
        if($validator->fails()){
            $this->error = $validator->errors()->toMsg();
            return false;
        }

        DB::beginTransaction();
        try {
            //流程类型
            $design = WorkflowDesign::where('guid',$data['design_id'])->first();
            if (!$design){
                throw new \Exception('参数错误 1001');
            }

            //dump($design);
            $data['tags'] = $design->title;
            $data['user_id'] = get_uuid();
            $wData = stayFill($this->fillable,$data);
            $wData['step'] = 1;
            //保存flow
            if (isset($data['wid']) && $data['wid']){
                $wData['is_filed'] = 0;
                $result = $this->where('guid',$data['wid'])->update($wData);
                $data['wid'] = $data['guid'];
            }else{
                $guid = getGuid();
                $wData['guid'] = $guid;
                $wData['work_no'] = date('YmdHis') . rand(1000000,9999999);
                $result = $this->create($wData);
                //
                $data['wid'] = $guid;
            }
            if (!$result){
                throw new \Exception('更新失败 1002');
            }
            //dump($wData);
            //保存信息
            $model = null;
            switch ($design->cid){
                case self::FLOW_INTERNS:
                    $model = new WorkflowInterns();
                    break;
                case self::FLOW_LEAVE:
                    $model = new WorkflowLeave();
                    break;
                case self::FLOW_PERSONNEL:
                    $model = new WorkflowPersonnel();
                    break;
            }
            if (!$model){
                throw new \Exception('未找到申请类型 1003');
            }
            $result = $model->changes( $data );
            if (false === $result){
                throw new \Exception($model->getError() . " 2001");
            }

            //保存附件
            if (isset($data['images']) && is_array($data['images'])){
                //保存请假时间
                $images = new WorkflowImages();
                $result = $images->changes($data);
                if (!$result){
                    $this->error = $images->getError();
                    return false;
                }
            }

            //开始流程
            $result = $this->sendBacklog($data['wid'],$design->guid,2,true);
            if (!$result){
                throw new \Exception($this->getError() . " 3001");
            }

            //操作记录
            $typeTitle = "创建";
            $type = isset($data['guid']) && $data['guid'] ? $data['guid'] : false;
            if ($type){
                $typeTitle = "重新提交";
            }
            $this->addHandleRecord($data['wid'],$typeTitle,$data['design_id'],0);
            /*dump($design->cid);
            dump($data);die;*/

            DB::commit();
            return true;
        }catch (\Exception $exception){
            DB::rollBack();
            $this->error = $exception->getMessage();
            return false;
        }
    }

    /*
     * 发送下一步审批人
     * */
    /*
     * 发送处理消息  给下一步人发送消息
     * @param wid
     * @param design_id
     * @param step
     * @param is_push
     * */
    public function sendBacklog($wid,$design_id,$step,$is_push=false)
    {
        $uid = get_uuid();
        $users = $this->getStepUser($wid,$design_id,$step,$uid,$is_push);
        /*dump($is_push);
        dump($users);die;*/
        //最终审核人
        $maxStep = WorkflowFlow::where('design_id',$design_id)->max('step');
        //dump($maxStep);
        //dump($step);die;
        if (!$users){
            $steps = $this->where('guid',$wid)->value('step');
            $steps = $steps + 1;
            //当前无负责人跳转下一步
            if ($step <= $maxStep){
                //流程步骤加1
                $work = $this->where('guid',$wid)->update([
                    'step'=>$steps,
                    'handle'=>$steps,
                ]);
                if (!$work){
                    $this->error = "code N100009";
                    return false;
                }

                return $this->sendBacklog($wid,$design_id,$step+1,$is_push);
            }else{
                //都没有人到最后一步 自己 归档
                //流程结束 归档 回调success
                $result = $this->successFlowFiled($wid,$steps);
                if (!$result){
                    $this->error = "code N100010";
                    return false;
                }
            }
        }

        //dump($users);die;

        //无上级 跳转下一步
        if ($is_push && $users){
            array_push($users,$uid);
        }

        $backLog = new WorkflowBacklog();
        foreach ($users as $key =>$item)
        {
            $step = $uid === $item ? $step - 1 : $step;
            /*dump($step);
            dump($item);die;*/
            $result = $backLog->changes($wid ,$design_id, $item,$step ,$uid);
            if (!$result){
                $this->error = "code N100011";
                break;
            }
        }
        return $step;
    }

    /*
     * 获取步骤所需要人员
     * */
    public function getStepUser($wid,$design_id,$step,$uid,$is_push=null)
    {
        //正常流程
        $info = DB::table('workflow_flow as f')
            ->leftJoin('workflow_flow_rule as r','f.guid','=','r.flow_id')
            ->where([
                'f.design_id'=>$design_id,
                'f.step'=>$step
            ])
            ->select([
                'f.title','f.step','r.type_id','r.approve_type','r.level','r.user_id','r.position_id'
            ])
            ->first();
        //dump($info);die;
        $userList  = [];
        switch ((int)$info->approve_type){
            case 1:
                //申请人
                $userList[] = get_uuid();
                break;
            case 2:
                //上级领导 第几个步骤的上级领导 而不是当前用户
                $parentId = getParentPersonId();
                if ($parentId){
                    $userList[] = $parentId;
                }
                break;
            case 3:
                //指定人员
                $userList[] = $info->user_id;
                break;
            case 5:
                //角色职位
                $parentId = getParentPersonId();
                if ($parentId){
                    $userList[] = $parentId;
                }
                break;
            case 6:
                //企业负责人
                $companyId = $this->where('guid',$wid)->value('company_id');
                $userList[] = $companyId;
                break;
            case 7:
                //学校负责人
                $schoolId = $this->where('guid',$wid)->value('school_id');
                $userList[] = $schoolId;
                break;
        }

        //dump($userList);die;

        return $userList;
    }

    /*
     * 处理审核工作
     * */
    public function approveWork( $data )
    {
        DB::beginTransaction();
        try {
            $wid = isset($data['wid']) ? $data['wid'] : false;
            if (!$wid){
                throw new \Exception("参数错误");
            }
            $info = $this->where('guid',$data['wid'])
                ->select("id","guid","design_id","step","is_filed","filed_time")
                ->first();
            if (!$info){
                $this->error = "信息错误 100001";
                return false;
            }
            if ($info->is_filed === 1){
                $this->error = "任务已完结";
                return false;
            }
            //dump($user);die;
            $uid = get_uuid();
            if (!$uid){
                throw new \Exception('身份信息有误');
            }
            $backLog = WorkflowBacklog::where([
                ['wid',$wid],
                ['uid',$uid],
            ])->first();
            if (!$backLog){
                throw new \Exception('信息错误 100002');
            }
            if ($backLog->is_audit !==0){
                throw new \Exception('已经审核过了，无需重复提交');
            }

            //dump($info);die;
            $type = isset($data['type']) ? $data['type'] : 'success';
            $where = [
                ['guid',$wid]
            ];
            $designId = $info->design_id;
            $step = $info->step;

            $audit = 0;

            switch ($type){
                case 'success':
                    $step = $step + 1;
                    //检测流程是否最后一步
                    $lastStep = get_last_flow($designId);
                    if ($step >= $lastStep){
                        //流程结束 归档 回调success
                        $result = $this->successFlowFiled($wid,$step);
                        if (!$result){
                            throw new \Exception('保存失败 SE00002');
                        }
                    }else if ($step > 0){
                        //给下一步的人推送信息
                        $nextStep = $step + 1;
                        //dump($nextStep);die;
                        $wStep = $this->sendBacklog( $wid,$designId,$nextStep );
                        if (!$wStep){
                            throw new \Exception('保存失败 SE00001');
                        }

                        $wStep = $wStep - 1;
                        //dump($wStep);die;
                        $result = $this->where('id',$info->id)->update(['step'=>$wStep]);
                        if (!$result){
                            throw new \Exception('保存失败 SE00002');
                        }
                    }
                    $audit = 1;
                    break;
                case 'reject':
                    $audit = -1;
                    //直接驳回到发起人
                    $result = $this->backSponsor( $wid );
                    if (!$result){
                        throw new \Exception('保存失败 BC10003');
                    }
                    $wStep = 0;
                    $result = $this->where($where)->update([
                        'step'=>$wStep
                    ]);
                    if (!$result){
                        throw new \Exception('保存失败 BC10005');
                    }
                    break;
            }
            //dump($info);die;
            //审核状态
            $remarks = isset($data['remarks']) ? $data['remarks'] : "";

            $backLog->is_audit = $audit;
            $backLog->remarks = $remarks;
            if (!$backLog->save()){
                throw new \Exception('审核失败 100007');
            }

            //添加修改记录
            $typeTitle = $audit === 1 ? "审核通过" : "驳回";
            $result = $this->addHandleRecord($wid,$typeTitle,$designId,$info->step,$remarks);
            if (!$result){
                throw new \Exception('保存失败 100008');
            }
            //dump($step);die;

            Db::commit();
            return  true;
        }catch (\Exception $exception){
            Db::rollback();
            $this->error  = $exception->getMessage();
            return false;
        }
    }

    /*
     * 添加操作记录
     * */
    public function addHandleRecord($wid,$type,$design_id,$step,$remarks='')
    {
        $user = get_user();
        if ((int)$step === 0){
            $stepTitle = "提交";
        }else{
            $stepTitle = WorkflowFlow::where([
                    ['design_id',$design_id],
                    ['step',$step+1]
                ])
                ->value('title');
        }
        $data = [
            'guid'=>getGuid(),
            'wid'=>$wid,
            'type'=>$type,
            'handle_name'=>$user->name,
            'uid'=>$user->guid,
            'step'=>$step+1,
            'step_title'=>$stepTitle,
            'remark'=>$remarks,
        ];
        $result = WorkflowHandleRecord::create($data);
        return $result;
    }

    /*
     * 驳回到发起人
     * */
    public function backSponsor( $wid )
    {
        $result = WorkflowBacklog::where([
            ['wid',$wid],
            ['step',1]
        ])->update([
            'is_audit'=>0,
            'remarks'=>NULL
        ]);
        if (!$result){
            return false;
        }
        return true;
    }

    /*
     * 流程结束 归档
     * @param workflow success
     * */
    public function successFlowFiled( $wid , $step )
    {
        //流程结束 归档 回调success
        $workflow = $this->where('guid',$wid)->first();
        if (!$workflow) {
            return false;
        }

        //开始其他任务处理
        //流程
        $design = WorkflowDesign::where('guid',$workflow->design_id)->first();
        if (!$design){
            return false;
        }
        $model = null;
        switch ($design->cid){
            case self::FLOW_INTERNS:
                $model = new WorkflowInterns();
                break;
            case self::FLOW_LEAVE:
                $model = new WorkflowLeave();
                break;
            case self::FLOW_PERSONNEL:
                $model = new WorkflowPersonnel();
                break;
        }
        if (!$model){
            throw new \Exception('未找到申请类型 1003');
        }
        $result = $model->successFlow( $workflow->guid );
        if (false === $result){
            throw new \Exception($model->getError() . " 2001");
        }

        $workflow->step = $step;
        $workflow->is_filed = 1;
        $workflow->filed_time = get_datetime();
        if (!$workflow->save()){
            return false;
        }

        return true;
    }



    /*
     * 获取信息
     * */
    public function getWorkflowInfo( $param )
    {
        $wid = isset($param['wid']) ? $param['wid'] : false;
        if (!$wid){
            $this->error = "参数错误";
            return false;
        }

        $where = [
            ['w.guid',$wid]
        ];
        //dump($where);die;
        $info = DB::table('workflow as w')
            ->leftJoin('workflow_design as d','w.design_id','=','d.guid')
            ->select([
                'w.guid as wid','w.step','w.work_no',
                'd.cid','d.title'
            ])
            ->where($where)
            ->first();
        if (!$info){
            $this->error = "信息不存在";
            return false;
        }

        $info = json_decode(json_encode($info),true);
        //dump($info);die;
        switch ($info['cid'])
        {
            case 1:
                $sonInfo = WorkflowInterns::where('wid',$wid)->first();
                $sonInfo = $sonInfo ? $sonInfo->toArray() : [];
                $info = array_merge($info,$sonInfo);
                break;
            case 2:
                $sonInfo = WorkflowLeave::where('wid',$wid)->first();
                $sonInfo = $sonInfo ? $sonInfo->toArray() : [];
                $info = array_merge($info,$sonInfo);
                break;
            case 3:
                $sonInfo = WorkflowPersonnel::where('wid',$wid)->first();
                $sonInfo = $sonInfo ? $sonInfo->toArray() : [];
                $info = array_merge($info,$sonInfo);
                break;
        }

        return $info;
    }


}
